#ifndef _GRO_BACKEND_SDL_GFX_H__
#define _GRO_BACKEND_SDL_GFX_H__

/*
 Contributed by: A. Schiffler, aschiffler at ferzkopp dot net
 */

/*
GRO_GUI backend: SDL_gfx

GRO_LineH
GRO_LineHBlend
GRO_LineV
GRO_LineVBlend
GRO_Line
GRO_LineBlend

GRO_Rect
GRO_RectBlend
GRO_RectFilled
GRO_RectFilledBlend
GRO_Circle
GRO_CircleBlend
GRO_CircleFilled
GRO_CircleFilledBlend
//GRO_Ellipse
//GRO_EllipseBlend
GRO_EllipseFilled
GRO_EllipseFilledBlend

GRO_TrigonFade
GRO_SetClip
GRO_DirtyAdd
GRO_RectIntersect

*/

#ifdef WIN32
#include "SDL_gfxPrimitives.h"
#else
#include "SDL/SDL_gfxPrimitives.h"
#endif 

#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)>(b)?(b):(a))

//#define RGB_FROM_COLOR(pixel, fmt, r, g, b) SDL_GetRGB(pixel, &fmt, &r, &g, &b)

#define RGB_FROM_COLOR(pixel, fmt, r, g, b)                             \
{                                                                       \
         r = ((pixel&fmt.Rmask)>>fmt.Rshift)<<fmt.Rloss;             \
         g = ((pixel&fmt.Gmask)>>fmt.Gshift)<<fmt.Gloss;             \
         b = ((pixel&fmt.Bmask)>>fmt.Bshift)<<fmt.Bloss;             \
}

#define COLOR_FROM_RGB(r, g, b) ((((((r << 8) | g) << 8) | b) << 8) | 0xFF)
#define COLOR_FROM_RGBA(r, g, b, a) ((((((r << 8) | g) << 8) | b) << 8) | a)

namespace GRO
{
    
    class Renderer_SDL_gfx : public Renderer
    {
        public:
        SDL_Surface* screen;
        Renderer_SDL_gfx()
            : Renderer()
            , screen(NULL)
        {}
        Renderer_SDL_gfx(SDL_Surface* screen)
            : Renderer()
        {
            this->screen = screen;
            if(screen != NULL && screen->format != NULL)
                format = *(screen->format);
        }
        
        virtual void Blit(SDL_Surface* image, SDL_Rect* s, SDL_Rect* d)
        {
            SDL_BlitSurface(image, s, screen, d);
        }
        
        virtual void Pixel(Sint16 x, Sint16 y, Uint32 color)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
            pixelColor(screen, x, y, color);
        }

        virtual void LineH(Sint16 x1, Sint16 y, Sint16 x2, Uint32 color)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
            hlineColor(screen, x1, x2, y, color);
        }

        virtual void LineHBlend(Sint16 x1, Sint16 y, Sint16 x2, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
            hlineRGBA(screen, x1, x2, y, cr, cg, cb, alpha);
        }

        virtual void LineV(Sint16 x, Sint16 y1, Sint16 y2, Uint32 color)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
            vlineColor(screen, x, y1, y2, color);
        }

        virtual void LineVBlend(Sint16 x, Sint16 y1, Sint16 y2, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
            vlineRGBA(screen, x, y1, y2, cr, cg, cb, alpha);
        }

        virtual void Line(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
            lineColor(screen, x1, y1, x2, y2, color);
        }

        virtual void LineBlend(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
            lineRGBA(screen, x1, y1, x2, y2, cr, cg, cb, alpha);
        }

        virtual void LineBlendAA(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
            aalineRGBA(screen, x1, y1, x2, y2, cr, cg, cb, alpha);
        }




        virtual void Rect(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
            rectangleColor(screen, x1, y1, x2, y2, color);
        }

        virtual void RectBlend(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
            rectangleRGBA(screen, x1, y1, x2, y2, cr, cg, cb, alpha);
        }

        virtual void RectFilled(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
			boxColor(screen, x1, y1, x2, y2, color);			
        }

        virtual void RectFilledBlend(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			boxRGBA(screen, x1, y1, x2, y2, cr, cg, cb, alpha);			
        }


                
        // Colors in CCW order
        virtual void RectFade(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint32 c1, Uint32 c2, Uint32 c3, Uint32 c4)
        {
            // use square box - faded box not supported by SDL_gfx
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(c1, format, cr, cg, cb);
			c1 = COLOR_FROM_RGB(cr, cg, cb);
			boxColor(screen, x1, y1, x2, y2, c1);
        }

        virtual void RectRound(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 radius, Uint32 color)
        {
            // use square rect - rounded rect not supported by SDL_gfx
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
            rectangleColor(screen, x1, y1, x2, y2, color);
        }

        virtual void RectRoundFilledBlend(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 radius, Uint32 color, Uint8 alpha)
        {
            // use square rect - rounded rect not supported by SDL_gfx
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			rectangleRGBA(screen, x1, y1, x2, y2, cr, cg, cb, alpha);
        }

        virtual void ArcBlend(Sint16 x, Sint16 y, Sint16 radius, float startAngle, float endAngle, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
            arcRGBA(screen, x, y, radius, startAngle, endAngle, cr, cg, cb, alpha);
        }


        virtual void Circle(Sint16 x, Sint16 y, Sint16 r, Uint32 color)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
            circleColor(screen, x, y, r, color);
        }

        virtual void CircleBlend(Sint16 x, Sint16 y, Sint16 r, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
            circleRGBA(screen, x, y, r, cr, cg, cb, alpha);
        }

        virtual void CircleFilled(Sint16 x, Sint16 y, Sint16 r, Uint32 color)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
            filledCircleColor(screen, x, y, r, color);
        }

        virtual void CircleFilledBlend(Sint16 x, Sint16 y, Sint16 r, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
            filledCircleRGBA(screen, x, y, r, cr, cg, cb, alpha);
        }

        virtual void EllipseFilled(Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
			color = COLOR_FROM_RGB(cr, cg, cb);
            filledEllipseColor(screen, x, y, rx, ry, color);
        }

        virtual void EllipseFilledBlend(Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint32 color, Uint8 alpha)
        {
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color, format, cr, cg, cb);
            filledEllipseRGBA(screen, x, y, rx, ry, cr, cg, cb, alpha);
        }

        virtual void TrigonFade(Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Sint16 x3, Sint16 y3, Uint32 color1, Uint32 color2, Uint32 color3)
        {
            // use only color1 - fade not supported by SDL_gfx
			Uint8 cr, cg, cb;
			RGB_FROM_COLOR(color1, format, cr, cg, cb);
			color1 = COLOR_FROM_RGB(cr, cg, cb);
            filledTrigonColor(screen, x1, y1, x2, y2, x3, y3, color1);
        }




        virtual SDL_Rect GetClip()
        {
            if(screen != NULL)
                return screen->clip_rect;
            SDL_Rect r = {0, 0, 0, 0};
            return r;
        }
        
        virtual void SetClip(SDL_Rect& clip)
        {
            if(screen != NULL)
				SDL_SetClipRect(screen, &clip);
        }

        virtual void DirtyAdd(SDL_Rect* rect)
        {
            // no-op - not supported by SDL_gfx
        }


        virtual void RectIntersect(const SDL_Rect& A, const SDL_Rect& B, SDL_Rect& intersection)
        {
			// Adapted from SDL_IntersectRect
			
            int resX, resY, resW, resH;
            int Amin, Amax, Bmin, Bmax;

            // Horizontal intersection
            Amin = A.x;
            Amax = Amin + A.w;
            Bmin = B.x;
            Bmax = Bmin + B.w;
            if(Bmin > Amin)
                    Amin = Bmin;
            resX = Amin;
            if(Bmax < Amax)
                    Amax = Bmax;
            resW = Amax - Amin > 0 ? Amax - Amin : 0;

            // Vertical intersection
            Amin = A.y;
            Amax = Amin + A.h;
            Bmin = B.y;
            Bmax = Bmin + B.h;
            if(Bmin > Amin)
                    Amin = Bmin;
            resY = Amin;
            if(Bmax < Amax)
                    Amax = Bmax;
            resH = Amax - Amin > 0 ? Amax - Amin : 0;

            intersection.x = resX;
            intersection.y = resY;
            intersection.w = resW;
            intersection.h = resH;
        }

        virtual void PushThickness(int thickness)
        {
            // no-op - not supported by SDL_gfx
        }

        virtual int PopThickness()
        {
            // no-op - not supported by SDL_gfx
			return 1;
        }
        
    };


}


#endif
